package BESA.DistributedBESA;

import java.io.Serializable;
import java.lang.reflect.Constructor;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
import java.util.ArrayList;
import java.util.Enumeration;

import BESA.Agent.StateBESA;
import BESA.Agent.StructBESA;
import BESA.Agent.Event.EventBESA;
import BESA.Exception.ExceptionBESARemote;
import BESA.Exception.ExceptionBESA_SendMessageError;
import BESA.SystemLevel.AdmBESA;
import BESA.SystemLevel.Directory.AgHandler;
import BESA.SystemLevel.Directory.greenpages.GreenPagesHelper;
import BESA.util.ReportBESA;
@SuppressWarnings("all")
public class AdmRemote extends UnicastRemoteObject implements AdmRemoteInterface, Serializable {
    /**
	 * 
	 */
	private static final long serialVersionUID = -5007140352266173409L;
	private static AdmBESA admLocal;

    public AdmRemote() throws RemoteException {
        super();
    }

    public AdmBESA getAdmLocal() {
        return admLocal;
    }

    public void synchronizeRemoteAgentDirectory(String admId,ArrayList agIdRemoteList, ArrayList aliasRemoteList) throws RemoteException {
			//actualizar los remotos en el directorio local
           	admLocal.updateAgentDirectory(admId,agIdRemoteList, aliasRemoteList);
            //callback para update de los locales en el remoto
			ArrayList idList = new ArrayList();
			ArrayList aliasList = new ArrayList();
			AdmRemote.admLocal.geLocalDirectoryList(idList,aliasList);
            //ESTA GENERANDO LA MISMA LISTA QUE ACABO DE RECIBIR
            //FUNCIONA PORQUE SON LISTAS VACIAS, COMO SE SOLUCIONA EL PROBLEMA
            // UTILIZAR EL ID DEL CONTENEDOR QUE INVOCA ESTE M�TODO REMOTO PARA
            //INVOCAR EL M�TODO AL OTRO LADO, Y SEGUNDA RETORNAR UN ARRAYLIST
            //PARA REGISTRAR LOS AGNETES DEL CONTENEDOR QUE ACABA DE SUBIR.
			this.updateRemoteAgentDirectory(AdmRemote.admLocal.getAdmHandler().getAdmId(),idList,aliasList);
    }


    public void updateRemoteAgentDirectory(String admId,ArrayList agIdList, ArrayList aliasList) throws RemoteException {
           	admLocal.updateAgentDirectory(admId,agIdList, aliasList);
    }

    public void importAgentDirectory(ArrayList adIdList, ArrayList aliasList) throws RemoteException {
		try{
			Enumeration keys = AdmRemote.admLocal.getAgIdTable().keys();
		    while (keys.hasMoreElements()) {
//se quita ojo		    	AgHandler agh = ((AgHandlerBESA)this.admLocal.getAgIdTable().get(keys.nextElement())).obtainAgLocal();
		    	AgHandler agh = ((AgHandler)AdmRemote.admLocal.getAgIdTable().get(keys.nextElement())).obtainAgLocal();
	        	if (agh != null) {
					//((AdmRemoteHandler)(this.admLocal.getAdmAliasTable().get(admAlias))).getAdmRemote().registerRemoteAgents (agh.getAlias(),agh.getAgId(),this.admLocal.getAdmHandler().getAlias());
					adIdList.add(agh.getAgId());
                    aliasList.add(agh.getAlias());
                    //ojo trae los locales y los remotos, que pueden ser locales mios
//					((AdmRemoteHandler)(this.admLocal.getAdmAliasTable().get(admAlias))).getAdmRemote().registerRemoteAgents (agh.getAlias(),agh.getAgId(),this.admLocal.getAdmHandler().getAlias());
		        }
		   	}
        }catch (Exception e) {
            throw new ExceptionBESARemote (e.toString());
        }

    }

	public void registerRemoteAgents(String agAlias, String agId, String admId) throws RemoteException{
		AdmRemote.admLocal.registerRemoteAgent(agAlias,agId,admId);
    }


    public void registerRemoteAdm(String admAlias, String ipAddress, int rmiPort) throws RemoteException {
        try {
	        AdmRemote.admLocal.registerRemoteAdm(admAlias, ipAddress, rmiPort);
        }
        catch (Exception e) {
            throw new ExceptionBESARemote (e.toString());
        }
    }

    public boolean registerRemoteAgent(String password, String administratorName, String aid) throws RemoteException{
        return true;
    }

    /**
     * unregisterRemoteAgent eliminar el registro remoto de un agente.
     * poner null a la tarjeta
     * @param password es la contrase�a del administrador local
     */
    public /*synchronized*/ void unregisterRemoteAgent(String password, String administratorName, String aid) throws RemoteException {
    }

    /**
     * createRemoteService
     * @param password es la contrase�a del administrador local
     * servName es el nombre oficial del servicios
     * descriptors son alias del servicio
     */
    public /*synchronized*/ void createRemoteService(String password, String servName, ArrayList descriptors) throws RemoteException {
    }

    /**
     * bindRemoteService
     * @param password es la contrase�a del administrador local
     * 
     */
    public /*synchronized*/ boolean bindRemoteService(String password, String aid, String servName) throws RemoteException {
        return true;
    }

    public void sendEvent(EventBESA ev, String aid) throws ExceptionBESA_SendMessageError, RemoteException {
		String msg = new String("");
        // Obtener tarjeta del destinatario
        // hacia el futuro se puede implantar un cache
		//se quita        AgHandlerBESA agh = (AgHandlerBESA)admLocal.getHandlerByAid(aid);
        AgHandler agh = (AgHandler)admLocal.getHandlerByAid(aid);
        if (agh == null) {
            // si el destinatario no existe -> send NO posible
           throw new ExceptionBESA_SendMessageError (ExceptionBESA_SendMessageError.EXCEPTION_HANDLERNULL);
        }
		//se quita else if (agh.getLocation()==agh.AG_LOCATION_LOCAL) {
        else{// if (agh.getAgHandlerBESA().getLocation()== AgHandlerBESA.AG_LOCATION_LOCAL) {
            try {
            	//se quita ((AgLocalHandler)agh).getAg().sendEvent(ev);
				//((AgHandler)agh).getAg().sendEvent(ev);
                agh.sendEvent(ev);
            }
            catch (Exception e) {
            	throw new ExceptionBESA_SendMessageError (ExceptionBESA_SendMessageError.EXCEPTION_HANDLERINVALID + e);
            }
        }
		//        else {       	throw new ExceptionBESA_SendMessageError (ExceptionBESA_SendMessageError.EXCEPTION_NOTLOCALAGENT);        }
    }

    public static void initAdmLocal(AdmBESA adm) {
        // init de la var estatica con control tipo singleton
        if (admLocal == null)
            admLocal = adm;
    }

  	public void moveAgentReceive(String aliasAg, StateBESA stateAg, StructBESA structAg, double passwdAg, String nameClassAgent) throws RemoteException{
		try{
			Class cls = Class.forName(nameClassAgent);
			Class[] partypes = new Class[4];
			partypes[0] = aliasAg.getClass();
			partypes[1] = stateAg.getClass();
			partypes[2] = structAg.getClass();
			Double password = new Double (passwdAg);
			partypes[3] = password.getClass();
			Constructor ct = cls.getConstructor(partypes);
			Object[] arglist = new Object[4];
			arglist[0] = aliasAg;
			arglist[1] = stateAg;
			arglist[2] = structAg;
			arglist[3] = new Double (passwdAg);
        	//Llamar contructora del agente con los parametros de la invocaci�n
			Object component = ct.newInstance(arglist);
		} catch (Exception e){
			ReportBESA.error("[AdmRemote:moveAgentReceive]:Error: No se puede hacer reflection del agente: "+ e);
		}
        //Ping para actualizar los directorios remotos
    }
  	public void moveAgentSend(String agId, String aliasDestinationAdm, double passwdAg) throws RemoteException{
		try {
			admLocal.moveAgent(agId, aliasDestinationAdm, passwdAg);
        }catch (Exception e) {
           	throw new ExceptionBESARemote ("[AdmRemote:moveAgentSend]: " + e.getMessage());
        }
    }

	@Override
	public void synchronizeRemoteGreenPages(GreenPagesHelper remoteGreenPages)throws RemoteException {
		GreenPagesHelper local = admLocal.getGreenPagesHelper();
		local.updateGreenPages(remoteGreenPages);
		
	}


}
